package org.bee.Interceptor.page;

import org.apache.ibatis.executor.parameter.ParameterHandler;
import org.apache.ibatis.executor.statement.StatementHandler;
import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.plugin.Interceptor;
import org.apache.ibatis.plugin.Intercepts;
import org.apache.ibatis.plugin.Invocation;
import org.apache.ibatis.plugin.Signature;
import org.apache.ibatis.reflection.MetaObject;
import org.apache.ibatis.reflection.SystemMetaObject;
import org.bee.PageUtil;
import org.bee.model.result.Page;

import java.lang.reflect.InvocationTargetException;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Properties;

/**
 * 分页拦截器，拦截mybatis的查询，处理分页参数
 */
@Intercepts({@Signature(type = StatementHandler.class,method = "prepare",args = {Connection.class,Integer.class})})
public class PageInterceptor implements Interceptor {

    @Override
    public Object intercept(Invocation invocation){
        StatementHandler statementHandler = (StatementHandler)invocation.getTarget();
        MetaObject metaObject = SystemMetaObject.forObject(statementHandler);
        Object proceed = null;
        try {
            BoundSql boundSql = statementHandler.getBoundSql();
            Page page = PageUtil.getPage();
            if(null==page){
                return invocation.proceed();
            }
            // 如果已经设置过总数，直接返回 用来确保有多个查询的时候以第一个的分页参数为准
            if(0!=page.getTotal()){
                return invocation.proceed();
            }
            String sql = boundSql.getSql();
            String countSql = "select count(0) from ("+sql+") tmp";
            Connection connection = (Connection) invocation.getArgs()[0];
            PreparedStatement countStatement = connection.prepareStatement(countSql);
            ParameterHandler parameterHandler = (ParameterHandler) metaObject.getValue("delegate.parameterHandler");
            parameterHandler.setParameters(countStatement);
            ResultSet rs = countStatement.executeQuery();
            if (rs.next()) {
                page.setTotal(rs.getInt(1));
            }
            rs.close();
            countStatement.close();
            long current = page.getCurrent();
            if(current==0){
                current = 1;
            }
            long offset  = (current-1)*page.getSize();
            String limit = String.format(" limit %s, %s",offset,page.getSize());
            sql+=limit;

            metaObject.setValue("delegate.boundSql.sql",sql);
            proceed = invocation.proceed();
        } catch (InvocationTargetException | IllegalAccessException | SQLException e) {
            throw new RuntimeException(e);
        }
        return proceed;
    }

    @Override
    public Object plugin(Object target) {
        return Interceptor.super.plugin(target);
    }

    @Override
    public void setProperties(Properties properties) {
        Interceptor.super.setProperties(properties);
    }
}
